/*
 * Copyright (c) 2011 Imre Fazekas.
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 * Neither the name of the Brillien nor the names of its
 * terms and concepts may be used to endorse or promote products derived from this
 * software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

package com.vii.brillien.ignition.jmx.mbeans;

import com.vii.brillien.ignition.jmx.BeanStatics;

import javax.management.Attribute;
import javax.management.MBeanServerConnection;
import javax.management.openmbean.CompositeData;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;

/**
 * Specialized AbstractBeanWrapper to provide ThreadMXBean services
 */
public class ThreadImpl extends AbstractBeanWrapper implements ThreadMXBean {

    public ThreadImpl( MBeanServerConnection mbsc ) {
        super( mbsc, BeanStatics.THREAD_BEAN_NAME );
    }

    public int getThreadCount() {
        return get(  "ThreadCount", -1 );
    }

    public int getPeakThreadCount() {
        return get(  "PeakThreadCount", -1 );
    }

    public long getTotalStartedThreadCount() {
        return get(  "TotalStartedThreadCount", -1l );
    }

    public int getDaemonThreadCount() {
        return get(  "DaemonThreadCount", -1 );
    }

    public long[] getAllThreadIds() {
        return get(  "AllThreadIds", null );
    }

    public ThreadInfo getThreadInfo(long id) {
        return ThreadInfo.from( invoke(  "getThreadInfo",
                new Object[]{ id },
                new String[]{ Long.TYPE.getName() },
                (CompositeData)null
        ) );
    }

    public ThreadInfo[] getThreadInfo(long[] ids) {
        CompositeData[] data = invoke(  "getThreadInfo",
                new Object[]{ ids },
                new String[] { "[J" },
                null
        );

        ThreadInfo[] infos = new ThreadInfo[ data == null ? 0 : data.length ];
        for( int i=0; i<infos.length; ++i )
            infos[ i ] = ThreadInfo.from( data[i] );

        return infos;
    }

    public ThreadInfo getThreadInfo(long id, int maxDepth) {
        return ThreadInfo.from( invoke(  "getThreadInfo",
                new Object[]{ id, maxDepth },
                new String[]{ Long.TYPE.getName(), Integer.TYPE.getName() },
                (CompositeData)null
        ) );
    }

    public ThreadInfo[] getThreadInfo(long[] ids, int maxDepth) {
        CompositeData[] data = invoke(  "getThreadInfo",
                new Object[]{ ids, maxDepth },
                new String[]{ "[J", Integer.TYPE.getName() },
                null
        );

        ThreadInfo[] infos = new ThreadInfo[ data == null ? 0 : data.length ];
        for( int i=0; i<infos.length; ++i )
            infos[ i ] = ThreadInfo.from( data[i] );

        return infos;
    }

    public boolean isThreadContentionMonitoringSupported() {
        return get(  "ThreadContentionMonitoringSupported", false );
    }

    public boolean isThreadContentionMonitoringEnabled() {
        return get(  "ThreadContentionMonitoringEnabled", false );
    }

    public void setThreadContentionMonitoringEnabled(boolean enable) {
        set( new Attribute("ThreadContentionMonitoringEnabled", enable) );
    }

    public long getCurrentThreadCpuTime() {
        return get(  "CurrentThreadCpuTime", -1l );
    }

    public long getCurrentThreadUserTime() {
        return get(  "CurrentThreadUserTime", -1l );
    }

    public long getThreadCpuTime(long id) {
        return invoke(  "getThreadCpuTime",
                new Object[]{ id },
                new String[]{ Long.TYPE.getName() },
                -1l
        );
    }

    public long getThreadUserTime(long id) {
        return invoke(  "getThreadUserTime",
                new Object[]{ id },
                new String[]{ Long.TYPE.getName() },
                -1l
        );
    }

    public boolean isThreadCpuTimeSupported() {
        return get(  "ThreadCpuTimeSupported", false );
    }

    public boolean isCurrentThreadCpuTimeSupported() {
        return get(  "CurrentThreadCpuTimeSupported", false );
    }

    public boolean isThreadCpuTimeEnabled() {
        return get(  "ThreadCpuTimeEnabled", false );
    }

    public void setThreadCpuTimeEnabled(boolean enable) {
        set( new Attribute( "ThreadCpuTimeEnabled", enable ) );
    }

    public long[] findMonitorDeadlockedThreads() {
        return invoke( "findMonitorDeadlockedThreads", null );
    }

    public void resetPeakThreadCount() {
        invoke(  "resetPeakThreadCount", null );
    }

    public long[] findDeadlockedThreads() {
        return invoke( "findDeadlockedThreads", null );
    }

    public boolean isObjectMonitorUsageSupported() {
        return get(  "ObjectMonitorUsageSupported", false );
    }

    public boolean isSynchronizerUsageSupported() {
        return get(  "SynchronizerUsageSupported", false );
    }

    public ThreadInfo[] getThreadInfo(long[] ids, boolean lockedMonitors, boolean lockedSynchronizers) {
        CompositeData[] data = invoke(  "getThreadInfo",
                new Object[]{ ids, lockedMonitors, lockedSynchronizers },
                new String[]{ "[J", Boolean.TYPE.getName(), Boolean.TYPE.getName() },
                null
        );

        ThreadInfo[] infos = new ThreadInfo[ data == null ? 0 : data.length ];
        for( int i=0; i<infos.length; ++i )
            infos[ i++ ] = ThreadInfo.from( data[i] );

        return infos;
    }

    public ThreadInfo[] dumpAllThreads(boolean lockedMonitors, boolean lockedSynchronizers) {
        CompositeData[] data = invoke(  "dumpAllThreads",
                new Object[]{ lockedMonitors, lockedSynchronizers },
                new String[]{ Boolean.TYPE.getName(), Boolean.TYPE.getName() },
                null
        );

        ThreadInfo[] infos = new ThreadInfo[ data == null ? 0 : data.length ];
        for( int i=0; i<infos.length; ++i )
            infos[ i ] = ThreadInfo.from( data[i] );

        return infos;
    }

}
